/*
 * @Author: 杨小灿jian308@qq.com
 * @Date: 2023-05-12 16:24:48
 * @LastEditors: 杨小灿jian308@qq.com
 * @LastEditTime: 2023-08-30 09:16:32
 */
package clog

import (
	"io"
	"os"
	"strconv"

	"gitee.com/jieyang/go/cjson"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"golang.org/x/sys/windows"
	"gopkg.in/natefinch/lumberjack.v2"
)

//日志需求
//开发模式全部打印
//发布模式可选不同等级输出文件跟控制台输出

// 默认直接可用
var logger zerolog.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "2006-01-02 15:04:05.000", NoColor: true}).With().Caller().Logger()

var lumberJackLogger *lumberjack.Logger

// 开发模式直接用默认的logger即可
func NewDevelopment() {
	logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "2006-01-02 15:04:05.000", NoColor: true}).With().Caller().Logger()
}

type clogLevelWriter struct {
	io.Writer
	Level zerolog.Level
}

func (w clogLevelWriter) WriteLevel(level zerolog.Level, p []byte) (int, error) {
	if level >= w.Level {
		return w.Write(p)
	}
	return len(p), nil
}

// 发布模式混合显示
// filename 日志文件地址
// 控制台输出日志等级
// 日志文件输出日志等级
// config按顺序看代码
func NewRelease(filename string, consoleLvInt, logfileLvInt int, config ...int) {
	//window下禁止控制台窗口的鼠标选择功能 防止日志输出卡死
	ForbiddenConsoleEdit()
	zerolog.InterfaceMarshalFunc = cjson.Marshal
	zerolog.TimeFieldFormat = "2006-01-02 15:04:05.000" //精确到微秒
	zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
		short := file
		for i := len(file) - 1; i > 0; i-- {
			if file[i] == '/' {
				short = file[i+1:]
				break
			}
		}
		file = short
		return file + ":" + strconv.Itoa(line)
	}
	consoleLv := zerolog.Level(consoleLvInt)
	logfileLv := zerolog.Level(logfileLvInt)
	// 使用 lumberjack 实现 log rotate
	MaxSize := 5
	MaxBackups := 30
	MaxAge := 1
	LocalTime := false
	Compress := false
	if config != nil {
		if len(config) > 0 {
			MaxSize = config[0]
		}
		if len(config) > 1 {
			MaxBackups = config[1]
		}
		if len(config) > 2 {
			MaxAge = config[2]
		}
		if len(config) > 3 {
			if config[3] > 0 {
				LocalTime = true
			}
		}
		if len(config) > 4 {
			if config[4] > 0 {
				Compress = true
			}
		}
	}
	consoleWriter := clogLevelWriter{
		Writer: zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "01-02 15:04:05", NoColor: true},
		Level:  consoleLv,
	}
	if lumberJackLogger != nil {
		lumberJackLogger.Close()
	}
	lumberJackLogger = &lumberjack.Logger{
		Filename:   filename,
		MaxSize:    MaxSize,    // 单个文件最大M
		MaxBackups: MaxBackups, // 多于 x 个日志文件后，清理较旧的日志
		MaxAge:     MaxAge,     // 一天一切割
		LocalTime:  LocalTime,
		Compress:   Compress,
	}
	fileWriteSyncer := clogLevelWriter{
		Writer: lumberJackLogger,
		Level:  logfileLv,
	}
	multi := zerolog.MultiLevelWriter(fileWriteSyncer, consoleWriter)
	logger = zerolog.New(multi).With().Timestamp().Caller().Logger()
}

func Info() *zerolog.Event {
	return logger.Info()
}

func Debug() *zerolog.Event {
	return logger.Debug()
}

func Error() *zerolog.Event {
	return logger.Error()
}

func Warn() *zerolog.Event {
	return logger.Warn()
}

// ForbiddenConsoleEdit 禁止控制台窗口的鼠标选择功能
func ForbiddenConsoleEdit() error {
	hConsole, err := windows.GetStdHandle(windows.STD_INPUT_HANDLE)
	if err == nil {
		mode := uint32(0)
		err = windows.GetConsoleMode(hConsole, &mode)
		if err == nil {
			mode &^= 0x0040
			if err := windows.SetConsoleMode(hConsole, mode); err != nil {
				return err
			} else {
				return nil
			}
		} else {
			return err
		}
	} else {
		return err
	}
}
